#include "XWindow.ph"
#ifdef __GNUG__
#pragma implementation
#endif

#include "X11.h"
#include "Port.h"
#include "XBitmap.h"
#include "XWinSystem.h"
#include "XWindowPort.h"
#include "String.h"
	
//---- XBitmap -----------------------------------------------------------------

XBitmap::XBitmap(const Point &sz, u_short *im, u_short dep, bool fd,
					u_short pad) : DevBitmap(sz, dep)
{
	if (dep <= 1)
		depth= 1;
	else if (dep <= 4)
		depth= 4;
	else if (dep <= 8)
		depth= 8;
	else if (dep <= 16)
		depth= 16;
	else if (dep <= 24)
		depth= 24;
	else
		depth= 32;
		
	inserver= FALSE;
	if (im) {
		freedata= fd;
		ximage= CreateImage(sz, depth, im, pad);
	} else {
		freedata= TRUE;
		ximage= 0;
	}
	pm= 0;
	gc= 0;
}

XBitmap::XBitmap(const Point &sz, XImage *im) : DevBitmap(sz, 1)
{
	freedata= TRUE;
	ximage= im;
	inserver= FALSE;
	pm= 0;
	gc= 0;
}

XBitmap::XBitmap(XBitmap *x) : DevBitmap(x)
{
	freedata= TRUE;
	ximage= XGetImage(XWinSystem::display, x->GetPixmap(), 0, 0,
				size.x, size.y, (u_long) AllPlanes, ZPixmap);
	inserver= FALSE;
	pm= 0;
	gc= 0;
}

XBitmap::~XBitmap()
{
	FreeImage();
	if (pm) {
		if (XWinSystem::display)
			XFreePixmap(XWinSystem::display, pm);
		pm= 0;
	}
	if (gc) {
		if (XWinSystem::display)
			XFreeGC(XWinSystem::display, gc);
		gc= 0;
	}
}

void XBitmap::FreeImage()
{
	if (ximage) {
		if (!freedata)
			ximage->data= 0;
		XDestroyImage(ximage);
		ximage= 0;
	}
}

DevBitmap *XBitmap::DevAllocBitmap(const Point &s, u_short d)
{
	return new XBitmap(s, 0, d);
}

DevBitmap *XBitmap::MakeCopy()
{
	return new XBitmap(this);
}

Pixmap XBitmap::GetPixmap()
{
	if (!inserver || pm == 0) {
		if (pm)
			XFreePixmap(XWinSystem::display, pm);
		pm= XWinSystem::CreatePixmap(size, depth);
		if (gc == 0)
			gc= XWinSystem::CreateGC(pm, 0, 0);
		if (ximage) {
			if (depth == 1) {
				XSetForeground(XWinSystem::display, gc, 1);
				XSetBackground(XWinSystem::display, gc, 0);
			}
			XPutImage(XWinSystem::display, pm, gc, ximage, 0, 0, 0, 0, size.x, size.y);
		} else {
			XSetFunction(XWinSystem::display, gc, GXclear);
			XFillRectangle(XWinSystem::display, pm, gc, 0, 0, size.x, size.y);
		}
		inserver= TRUE;
	}
	return pm;
}

XImage *XBitmap::getImage()
{
	FreeImage();
	if (pm)
		ximage= XGetImage(XWinSystem::display, pm, 0, 0, size.x, size.y,
								(u_long) AllPlanes, ZPixmap);
	else
		ximage= CreateImage(size, depth);
	freedata= TRUE;
	inserver= FALSE;
	return ximage;
}

XImage *XBitmap::CreateImage(Point s, u_int d, u_short *data, u_short pad)
{
	short ss= 0x0100;
	char *cp= (char*) &ss;
	XImage *im;

	im= XCreateImage(XWinSystem::display, XWinSystem::dfltvisual,
		d, d == 1 ? XYBitmap : ZPixmap, 0, (char*) data, s.x, s.y, pad*8, 0);
	if (im->data == 0)
		im->data= (char*)Storage::_Calloc(s.y, im->bytes_per_line);
	im->byte_order= (*cp) ? MSBFirst : LSBFirst;
	im->bitmap_bit_order= MSBFirst;
	im->bitmap_unit= pad*8;
	im->bits_per_pixel= d;

	return im;
}

void XBitmap::DevMapColors(DevBitmap *src, u_long *map)
{
	register int x, y;
	XImage *im= GetImage(), *simage= ((XBitmap*)src)->GetImage();

	if (0 && depth == 8 && src->depth == 8) {
		register byte *to= (byte*)im->data, *from= (byte*)simage->data;
		register int l= im->bytes_per_line * size.y;
		register u_long *m= map;
		while (l--)
			*to++= (byte) m[*from++];
	} else {
		for (x= 0; x < size.x; x++)
			for (y= 0; y < size.y; y++)
				XPutPixel(im, x, y, map[XGetPixel(simage, x, y)]);
	}
}

void XBitmap::ReadData(BitmapInfo *bi, IStream &is)
{
	if (bi->bitsperpixel == 1 || bi->bitsperpixel == 8
						|| bi->bitsperpixel == 16 || bi->bitsperpixel == 32) {
		FreeImage();
		ximage= CreateImage(size, bi->bitsperpixel, 0, bi->rowpad);
		freedata= TRUE;
		is.read((byte*)ximage->data, ximage->bytes_per_line * size.y);
	} else
		DevBitmap::ReadData(bi, is);
}

void XBitmap::SetRow(BitmapInfo *bi, int row, byte *rowdata)
{
	GetImage();
	if (bi->bitsperpixel == 1 || bi->bitsperpixel == 4 || bi->bitsperpixel == 8) {
		byte *to= &((byte*)ximage->data)[row*ximage->bytes_per_line];
		MemCpy(to, rowdata, ximage->bytes_per_line);
	} else
		DevBitmap::SetRow(bi, row, rowdata);
}

u_long XBitmap::GetPixel(u_int x, u_int y)
{
	return (u_long) XGetPixel(GetImage(), x, y);
}

void XBitmap::SetPixel(u_int x, u_int y, u_long value)
{
	XPutPixel(GetImage(), x, y, value);
}

void XBitmap::DevBitBlt(int x, int y, int w, int h, BitBltOp op,
				DevBitmap *src, int sx, int sy, u_long val)
{
	XBitmap *b= (XBitmap*) src;
	GetPixmap();
	switch (op) {
	case eBitCopy:
		XSetFunction(XWinSystem::display, gc, GXcopy);
		XCopyArea(XWinSystem::display, b->GetPixmap(), pm, gc, sx, sy, w, h, x, y);
		break;
	case eBitOr:
		XSetFunction(XWinSystem::display, gc, GXor);
		XCopyArea(XWinSystem::display, b->GetPixmap(), pm, gc, sx, sy, w, h, x, y);
		break;
	case eBitSet:
		XSetFunction(XWinSystem::display, gc, GXcopy);
		XSetForeground(XWinSystem::display, gc, val);
		XFillRectangle(XWinSystem::display, GetPixmap(), gc, x, y, w, h);
		break;
	}
}

